import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:gim_plugin_example/config.dart';
import 'package:gim_plugin_example/consts.dart';
import 'package:gim_plugin_example/utils/cache.dart';
import 'package:gim_plugin_example/utils/platform_utils.dart';
import 'package:gim_plugin_example/utils/toast_utils.dart';

import 'data_utils.dart';
import 'logger_utils.dart';

enum ApiMethod { get, post, put, delete }

class Api {
  final String url;
  final ApiMethod method;

  Api(this.url, this.method);
}

class Dto {
  String? _code;
  String? _message;
  dynamic _data;

  String? get code => _code;

  dynamic get message => _message;

  dynamic get data => _data;

  Dto.fromJson(dynamic json) {
    _code = json["code"];
    _message = json["message"];
    _data = json["data"];
  }

  @override
  String toString() {
    return 'Dto{_code: $_code, _message: $_message, _data: $_data}';
  }
}

typedef OnError = Function({String? code, String? msg});

class Ajax {
  final Dio _dio = Dio();

  Ajax() {
    _dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options, RequestInterceptorHandler handler) {
      handler.next(options);
    }, onResponse: (Response response, ResponseInterceptorHandler handler) {
      String sep = "\n================================= 网络请求 =================================";
      var options = response.requestOptions;
      String url = "url = ${options.uri.toString()} ${options.method.toString()}";
      String header = "headers = ${options.headers}";
      String params = "reqParams = ${options.queryParameters}";
      String body = "reqBody = ${options.data}";
      String code = "respCode = ${response.statusCode}";
      var resp = "response = ${response.data}";
      loggerDebug('$sep\n$url\n$params\n$body\n$code\n$header\n$resp\n');
      handler.next(response);
    }, onError: (DioError e, ErrorInterceptorHandler handler) {
      String sep = "\n================================= 错误网球请求 =================================";
      var options = e.requestOptions;
      String url = "url = ${options.uri.toString()} ${options.method.toString()}";
      String params = "reqParams = ${options.queryParameters}";
      String body = "reqBody = ${options.data}";
      String errType = "errType = ${e.type}";
      String errMsg = "errMsg = ${e.message}";
      String stackTrace = "stackTrace = ${e.stackTrace}";
      loggerDebug('$sep\n$url\n$params\n$body\n$errType\n$errMsg\n$stackTrace\n');
      handler.next(e);
    }));
  }

  Future<Map<String, dynamic>> _getHeaders(Map<String, dynamic>? headers) async {
    headers ??= {};
    headers['appId'] = APP_ID;
    headers['platform'] = await getPlatformInfo();
    headers['version'] = VERSION;
    headers["ts"] = '${DateTime.now().millisecondsSinceEpoch}';
    headers[TOKEN] = cache.getStringSync(TOKEN);
    return headers;
  }

  Future<dynamic> _request(Api api,
      {String? host,
      Map<String, dynamic>? queryParams,
      dynamic pathParam,
      Map<String, dynamic>? data,
      Map<String, dynamic>? headers}) async {
    if (isBlack(host)) {
      host = srvHost;
    }
    String url = host! + api.url;
    if (pathParam != null) {
      if (api.url.endsWith("/")) {
        url = '$url$pathParam';
      } else {
        url = '$url/$pathParam';
      }
    }
    Response response;
    switch (api.method) {
      case ApiMethod.get:
        response = await _dio.get(url, queryParameters: queryParams, options: Options(headers: headers));
        break;
      case ApiMethod.post:
        response = await _dio.post(url,
            queryParameters: queryParams,
            data: json.encode(data ?? {}),
            options: Options(headers: headers, contentType: "application/json;charset=UTF-8"));
        break;
      case ApiMethod.put:
        response = await _dio.put(url,
            queryParameters: queryParams,
            data: json.encode(data ?? {}),
            options: Options(headers: headers, contentType: "application/json;charset=UTF-8"));
        break;
      case ApiMethod.delete:
        response = await _dio.delete(url, queryParameters: queryParams, options: Options(headers: headers));
        break;
      default:
        response = await _dio.patch(url, queryParameters: queryParams, options: Options(headers: headers));
    }
    return response;
  }

  Future<dynamic> request(Api api,
      {String? host,
      Map<String, dynamic>? queryParams,
      dynamic pathParam,
      Map<String, dynamic>? data,
      Map<String, dynamic>? headers,
      OnError? onError,
      Interceptor? interceptor}) async {
    Response? response;
    try {
      headers ??= {};
      headers = await _getHeaders(headers);
      response =
          await _request(api, host: host, queryParams: queryParams, pathParam: pathParam, data: data, headers: headers);
      if (response == null || response.data == null) {
        showToast('网络错误，请稍后尝试');
        return null;
      }
    } catch (e) {
      return null;
    }
    var dto = Dto.fromJson(response.data);
    return parseDto(dto: dto, onError: onError);
  }

  dynamic parseDto({Dto? dto, OnError? onError}) {
    if (dto == null) {
      showToast("网络错误,请稍后重试");
      if (onError != null) {
        onError(code: "ERROR", msg: "网络错误,请稍后重试");
      }
      return null;
    }
    if (dto.code != 'OK') {
      if (dto.code != 'ApiTokenErr') {
        showToast(dto.message);
      }
      if (onError != null) {
        onError(code: dto.code, msg: dto.message);
      }
      return null;
    }
    return dto.data;
  }
}

Ajax ajax = Ajax();
